#include <iostream>
#include <string>
#include "arbre.hpp"
#include "affichage.hpp"

using namespace std;

void aide();
void testArbre(unsigned int numTest, bool affE, bool affH, bool affV, bool valeur);

int main(int argc, char* argv[])
{
    if(argc < 2)
    {
        aide();
        return EXIT_FAILURE;
    }

    bool help = false; // affichage de l'aide
    bool aff_expr = false; // affichage en expression
    bool aff_hor = false; // affichage de l'arbre en mode horizontal
    bool aff_ver = false; // affichage de l'arbre en vertical
    bool valeur = false;
    bool test = false; // si le programme doit faire un test pré-créé
    int num_test = 0;

    for(int i = 1; i<argc-1; i++)
    {
        string str = argv[i];
        //cout << str << endl;
        if(str == "-e" || str == "--expression") {
            aff_expr = true;
        } else if (str == "-v" || str == "--vertical") {
            aff_ver = true;
        } else if (str == "-h" || str == "--horizontal") {
            aff_hor = true;
        } else if (str == "-t" || str == "--test") {
            test = true;
        } else if (str == "--valeur") {
            valeur = true;
        } else if (str == "--help") {
            help = true;
        }else {
            cout << "l'argument " << str << " n'est pas pris en compte par le programme. Utilisez l'argument --help pour plus d'information" << endl;
                return EXIT_FAILURE;
        }
    }

    if(!aff_expr && !aff_hor) // l'affichage vertical est choisi par défaut
    {
        aff_ver = true;
    }

    string str = argv[argc-1];


    if((str.compare("--help") == 0) || help == true)
    {
        aide();
        return EXIT_SUCCESS;
    }
    else if (test)
    {
        num_test = atoi(str.c_str());
        if(num_test < 0)
        {
            cout << "un test est réferencé par un numéro plus grand que 0" << endl;
            return EXIT_FAILURE;
        } else {
            testArbre(num_test, aff_expr, aff_hor, aff_ver, valeur);
            return EXIT_SUCCESS;
        }
    } else {
        str = enleveChar(str, ' ');
        str = enleveParentheseAutour(str);
        if(verifieExpressionPolonaise(str))
        {
            arbre a;
            initArbre(a, str);

            if (aff_expr)
            {
                affichageArbreExpression(a);
            }

            if (aff_hor)
            {
                affichageArbreHorizontal(a);
            }

            if (aff_ver)
            {
                affichageArbreVertical(a);
            }

            if(valeur)
                cout << "l'arbre vaut : " << valeurArbre(a) << endl;
            testamentArbre(a);
            return EXIT_SUCCESS;
        }
        else
            return EXIT_FAILURE;
    }

    return 0;
}

void aide()
{
    cout << "utilisation du programme :" << endl;
    cout << "./arbre [arguments] [expression|entier]" << endl;
    cout << "les arguments sont :" << endl;
    cout << "\t--valeur : affiche la valeur de l'arbre" << endl;
    cout << "\t-e ou --expression : affiche l'arbre sous forme d'expression arithémtique" << endl;
    cout << "\t-h ou --horizontal : affiche l'arbre sous forme horizontale" << endl;
    cout << "\t-v ou --vertical : affiche l'arbre sous forme verticale (affichage par défaut)" << endl;
    cout << "\t   si un mode d'affichage est précisé il faut repréciser si vous voulez afficher l'arbre sous forme verticale" << endl;
    cout << "\t   plusieurs arguments d'affichage peuvent êtres mis ensembles" << endl;
    cout << "\t-t ou --test : l'arbre est créé a partir d'un jeu de tests" << endl;
    cout << "\t   et argument doit être suivit d'un entier compris entre 1 et 3" << endl;
    cout << "\t   voir le README pour les tests proposés" << endl;
    cout << "\t--help : affiche l'aide" << endl;
    cout << endl;
    cout << "l'expression doit être de la forme polonaise inversée" << endl;
    cout << "soit de la forme op(expr)(expr)...(expr)" << endl;
    cout << "où op représente l'opérateur + ou *" << endl;
    cout << "et expr représente une expression ou une valeur" << endl;
    cout << "un arbre peut être égal a seulement une valeur" << endl;
}

void testArbre(unsigned int numTest, bool affE, bool affH, bool affV, bool valeur)
{
    switch (numTest) {
        case 1 : {
            arbre a, b, c, ab, somme;
            initArbre(a, 1);
            initArbre(b, 2);
            initArbre(c, 3);
            initArbre(ab);
            initArbre(somme);
            addArbre(a, b, ab);
            addArbre(ab, c, somme);

            if(affE)
                affichageArbreExpression(somme);
            if(affH)
                affichageArbreHorizontal(somme);
            if(affV)
                affichageArbreVertical(somme);
            if(valeur)
                cout << "l'arbre vaut : " << valeurArbre(somme) << endl;

            testamentArbre(a);
            testamentArbre(b);
            testamentArbre(c);
            testamentArbre(ab);
            testamentArbre(somme);
            break;
        }

        case 2 : {
            arbre a, b, mult;
            string exprA = "+(1)(2)", exprB = "+(3)(4)(5)";
            initArbre(a, exprA);
            initArbre(b, exprB);
            initArbre(mult);
            multArbre(a, b, mult);

            if(affE)
                affichageArbreExpression(mult);
            if(affH)
                affichageArbreHorizontal(mult);
            if(affV)
                affichageArbreVertical(mult);
            if(valeur)
                cout << "l'arbre vaut : " << valeurArbre(mult) << endl;

            testamentArbre(a);
            testamentArbre(b);
            testamentArbre(mult);
            break;
        }

        case 3 : {
            arbre a, b, mult, dev;
            string exprA = "+(1)(2)", exprB = "+(3)(4)(5)";
            initArbre(a, exprA);
            initArbre(b, exprB);
            initArbre(mult);
            multArbre(a, b, mult);
            initArbre(dev);
            developpeProduitArbre(mult, dev);

            if(affE)
                affichageArbreExpression(dev);
            if(affH)
                affichageArbreHorizontal(dev);
            if(affV)
                affichageArbreVertical(dev);
            if(valeur)
                cout << "l'arbre vaut : " << valeurArbre(dev) << endl;

            testamentArbre(a);
            testamentArbre(b);
            testamentArbre(mult);
            testamentArbre(dev);
            break;
        }

        default:
            cout << "vous avez entré un nombre trop grand. Les test sont numérotés de 1 à 3" << endl;
            break;
    }
}
